-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Add TCPKeepAlive to SqlClient Sockets #33024
Conversation
#if netcoreapp | ||
// enable keep-alive on socket | ||
const int time = 30; | ||
const int interval = 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These probably don't need to be constants and can just be passed directly into the method calls... the names here don't really add anything. If we do keep the consts, though, they should be PascalCased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
CI tests are failing on All configurations:
Given from the configurations in System.Net.Sockets.csproj I see it's configured to these settings: @stephentoub @weshaggard could you please confirm if I had taken the right approach? |
@dotnet-bot test Linux arm64 Release Build |
@@ -223,6 +223,16 @@ void Cancel() | |||
if (ipAddresses[i] != null) | |||
{ | |||
sockets[i] = new Socket(ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp); | |||
#if netcoreapp | |||
#if uapassembly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're only doing this if this is both netcoreapp and uapassembly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I am not sure if this is the proper way though, I need some guidance. As I mentioned, the configurations in System.Net.Sockets.csproj are set for netcoreapp and uap only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@afsanehr I think you only need the #if netcoreapp, here. This code will only be compiled when SqlClient is running on .Net Core on UWP. And not for other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saurabh500 I originally had it for netcoreapp and the AllConfigurations build was failing for these error messages still:
System\Data\SqlClient\SNI\SNITcpHandle.cs(231,92): error CS0117: 'SocketOptionName' does not contain a definition for 'TcpKeepAliveInterval' [D:\j\workspace\windows-TGrou---0d2c9ac4\src\System.Data.SqlClient\src\System.Data.SqlClient.csproj]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to failing CI using netcoreapp only: https://ci3.dot.net/job/dotnet_corefx/job/master/job/windows-TGroup_all+CGroup_Debug+AGroup_x64+TestOuter_false_prtest/17322/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is not an answer that will solve all the scenarios but we generally use netcoreapp and let it float and when we remap netcoreapp to the next version we generally leave behind a specific version for the older version as necessary and it is at that time we many need to adjust the defines to also include the older version.
For reference our guidance is at https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/project-guidelines.md#conventions-for-forked-code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have the feature flag for netcoreapp, and going forward, any netcoreapp version would definitely have these APIs in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you could define that layering in your project. However we generally haven't made netcoreapp also imply uap which is why I suggested feature define and how you determine to define that in your project is up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. The UAP here is unnecessary and should be removed. This will end up being a DefineConstant with a TargetGroup == netcoreapp check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @weshaggard
#if netcoreapp | ||
#if uapassembly | ||
// enable keep-alive on socket | ||
const int Time = 30; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get rid of these const and simply inline the value in API call.
// enable keep-alive on socket | ||
sockets[i].SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); | ||
sockets[i].SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1000); | ||
sockets[i].SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 30); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in minutes, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saurabh500 Good question .. I am trying to look for documentation . I see here it mentions in milliseconds:
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc782936(v=ws.10)
This user also mentioned the options are milliseconds here:
https://github.com/dotnet/corefx/issues/25040
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need 30 minutes. 30 Millis doesn't make sense. I wonder how Karl came up with this value. Can you sync with him?
Native SNI uses 30 minutes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to these links:
1- https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
2- http://man7.org/linux/man-pages/man7/tcp.7.html
The measurements for the TcpKeepAliveInterval
and TcpKeepAliveTime
in Windows and Linux OS are different. In Linux the TCP_KEEPINTVL
and TCP_KEEPIDLE
is set in seconds, while in Windows these values are measured in milliseconds.
Should we have different values based on different platform?
@stephentoub @karelz Do you know if this is something we can get some guidance from System.Net.sockets area owners?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have different values based on different platform?
@stephentoub @karelz Do you know if this is something we can get some guidance from System.Net.sockets area owners?
No, otherwise it makes it really difficult to use. Since these are already different settings on the different platforms and the Sockets class is trying to provide an abstraction over them, it should also be normalizing the units. If it's not, that's a bug and we should fix it.
@afsanehr, can you open an issue tracking that? Thanks.
cc: @luigiberrettini
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As highlighted in #25040 TCP_KEEPALIVE
/ TCP_KEEPIDLE
and TCP_KEEPINTVL
are expressed in seconds while SIO_KEEPALIVE_VALS
are expressed in milliseconds.
Since #29963 allows to set keep-alive retry count, time and interval on all platforms, but without making the developer life easier, there is still the need to code the logic that allow to use the proper socket method depending on the operating system and its version:
// *** Retry count
// Win 2000, Win XP, Win Server 2003
// - no change via socket methods
// - value is 5 or min(255, max(TcpMaxDataRetransmissions, PPTPTcpMaxDataRetransmissions))
// Win Vista and later < Win 10 v1703
// - no change via socket methods
// - value is 10
// Linux, OS X, Windows >= Win 10 v1703
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, RetryCount);
// *** Time and interval
// Windows < Win 10 v1709
socket.IOControl(IOControlCode.KeepAliveValues, byteArrayWithTimeAndIntervalMilliseconds, null);
// Linux, OS X, Windows >= Win 10 v1709
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, TimeSeconds);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, IntervalSeconds);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is still the need to code the logic that allow to use the proper socket method depending on the operating system and its version:
For time and interval, why can't we just make this work from the .net layer? We'd just translate the SetSocketOption to the appropriate call on a lower version of Windows, and we'd ensure the. NET API is consistent on units.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since IOControl accept a structure with on/off, time and interval, if a developer wants to set only time or interval, which value would you use for the other?
Moreover, when a user tries to set both with two different SetSocketOption calls, the second call will override what has been set by the first call.
I think we can either keep things as they are (every dev will have to write the logic) or create an API that expect a bool (enable/disable) and the three values to be passed: this would allow performing individual SetSocketOption or other calls under the hood.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stephentoub created issue #33111 for tracking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@afsanehr I want to correct my statement, the keep alive time should be 30 seconds. And the KeepAlive interval should be 1 second.
Values from Windows code in milliseconds.
DWORD const KEEPALIVETIME = 30000;
DWORD const KEEPALIVEINTERVAL = 1000;
@dotnet-bot test Linux arm64 Release Build |
@dotnet-bot test Linux arm64 Release Build |
@afsanehr we'd like to port this change to release/2.2 once it's merged. Do you know what we're waiting on? I know for macOS\Linux the interval needs to be changed to 1, and given the current implementation of the Socket option, we'd need a conditional to use 30000\1000 on Windows, and then presumably a different branch for download level Windows clients to use IOControl. Please let me know if you would like help make these modifications, as we'd like to get this into release/2.2 as soon as possible. |
@stephentoub we are working with shiproom to get the SqlClient and Sockets KeepAlive changes backported to release/2.2. I'll add you to the email thread for additional context and to provide feedback. |
@kburtram Sure, I will update this today and will ask you for review. |
@@ -223,6 +223,10 @@ void Cancel() | |||
if (ipAddresses[i] != null) | |||
{ | |||
sockets[i] = new Socket(ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp); | |||
#if FEATURE_TCPKEEPALIVE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this If check. For other platforms, an empty function will be compiled.
internal partial class SNITcpHandle | ||
{ | ||
internal static void SetKeepAliveValues(ref Socket socket) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment in the function saying why it has been left blank. Possible add the link to the issue, that we discussed should be opened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved with some suggestions.
@dotnet-bot test Windows x86 Release Build |
@kburtram Discussed with @saurabh500 and we decided to add a class SNITcpHandle.unix to set the keepAlive values. |
@dotnet-bot test UWP NETNative x86 Release Build |
@dotnet-bot test NETFX x86 Release Build |
@dotnet-bot test Windows x64 Debug Build |
@dotnet-bot test Windows x64 Debug Build Timeout exceeded. |
@dotnet-bot test Windows x64 Debug Build Timeout exceeded. |
@dotnet-bot test Windows x64 Debug Build |
How to find original issue #28061 ? |
* Updating version files * Enable keep alive on SqlClient TCP sockets * make KeepAlive netcoreapp specific * added condition for uapassembly * added a new defineConstants called FEATURE_TCPKEEPALIVE * update TCPKeepAliveInterval value * set KeepAlive values in unix only * add documentation and add link to Github Issue * move SNITcpHandle.Windows.cs available in UAP * updating csproj for SNITcpHandle * fix in csproj for CI failure Commit migrated from dotnet/corefx@0db2274
Fixes #28061.